#include <iostream>
#include <fstream>
#include <cctype>
#include <string>
#include <unordered_map>

using namespace std;

// TODO:是否修改编号？？
// 关键字及编号
unordered_map<string, int> keywords = {
    {"int", 1}, {"void", 2}, {"return", 3}, {"const", 4}, {"main", 5}, {"float", 6}, {"if", 7}, {"else", 8}};

// 运算符及编号
unordered_map<string, int> operators = {
    {"+", 9}, {"-", 10}, {"*", 11}, {"/", 12}, {"%", 13}, {"=", 14}, {">", 15}, {"<", 16},
    {"==", 17}, {"<=", 18}, {">=", 19}, {"!=", 20}, {"&&", 21}, {"||", 22}};

// 界符及编号
unordered_map<char, int> separators = {
    {'(', 23}, {')', 24}, {'{', 25}, {'}', 26}, {';', 27}, {',', 28}};

void lexicalAnalyze(const string &inputFilename, const string &outputFilename)
{
    ifstream fin(inputFilename);
    if (!fin)
    {
        cerr << "无法打开文件: " << inputFilename << endl;
        return;
    }

    ofstream fout(outputFilename);
    if (!fout)
    {
        cerr << "无法创建输出文件: " << outputFilename << endl;
        return;
    }

    char ch;
    while (fin.get(ch))
    {
        if (isspace(ch))
            continue;

        if (isalpha(ch) || ch == '_')
        {
            string token(1, ch);
            while (fin.peek() != EOF && (isalnum(fin.peek()) || fin.peek() == '_'))
            {
                token += fin.get();
            }
            if (keywords.count(token))
            {
                string output = token + " <KW," + to_string(keywords[token]) + ">";
                cout << output << endl;
                fout << output << endl;
            }
            else
            {
                string output = token + " <IDN," + token + ">";
                cout << output << endl;
                fout << output << endl;
            }
        }
        else if (isdigit(ch))
        {
            string num(1, ch);
            bool isFloat = false;

            while (isdigit(fin.peek()))
            {
                num += fin.get();
            }

            if (fin.peek() == '.')
            {
                isFloat = true;
                num += fin.get();
                while (isdigit(fin.peek()))
                {
                    num += fin.get();
                }
            }

            if (isFloat)
            {
                string output = num + " <FLOAT," + num + ">";
                cout << output << endl;
                fout << output << endl;
            }
            else
            {
                string output = num + " <INT," + num + ">";
                cout << output << endl;
                fout << output << endl;
            }
        }
        else if (ispunct(ch))
        {
            string op(1, ch);
            char next = fin.peek();
            if (next != EOF)
            {
                string twoCharOp = op + next;
                if (operators.count(twoCharOp))
                {
                    fin.get();
                    string output = twoCharOp + " <OP," + to_string(operators[twoCharOp]) + ">";
                    cout << output << endl;
                    fout << output << endl;
                    continue;
                }
            }
            if (operators.count(op))
            {
                string output = op + " <OP," + to_string(operators[op]) + ">";
                cout << output << endl;
                fout << output << endl;
            }
            else if (separators.count(ch))
            {
                string output = ch + string(" <SE,") + to_string(separators[ch]) + ">";
                cout << output << endl;
                fout << output << endl;
            }
            else
            {
                string output = ch + string(" <UNKNOWN,?>");
                cout << output << endl;
                fout << output << endl;
            }
        }
        else
        {
            string output = ch + string(" <UNKNOWN,?>");
            cout << output << endl;
            fout << output << endl;
        }
    }

    fin.close();
    fout.close();
}

int main()
{
    string inputFilename = "source.sy";
    string outputFilename = "../parser/token.tsv"; 
    lexicalAnalyze(inputFilename, outputFilename);
    cout << "词法分析完成，结果已写入 " << outputFilename << endl;
    return 0;
}
